import { InfiniteScrollViewCpnt, IsvPageExtraMode } from "./InfiniteScrollViewCpnt";

const { ccclass, property } = cc._decorator;

let AutoPageActionTime = 0.5 // 自动轮播时间

// 无限轮播列表组件
@ccclass
export class InfinitePageViewCpnt extends cc.Component {
    @property(cc.Node)
    ndIsvCpntCtn: cc.Node = null
    @property(cc.Prefab)
    pfbIsvCpnt: cc.Prefab = null
    @property(cc.Boolean)
    isHorizontal: boolean = true
    @property(cc.Integer)
    itemTopOrLeftSpace: number = 0
    @property(cc.Integer)
    itemSpace: number = 0
    @property(cc.Integer)
    itemBottomOrRightSpace: number = 0
    @property(cc.Integer)
    autoPageTime: number = 0
    @property(cc.Boolean)
    infinity: boolean = true
    @property(cc.Node)
    indicator: cc.Node = null
    @property({
        tooltip: CC_DEV && `是否显示指示器`
    })
    isIndicatorActive: boolean = false
    @property({
        tooltip: CC_DEV && `i18n:COMPONENT.layout.affected_by_scale`
    })
    affectedByScale: boolean = true

    ndItemForTest: cc.Node
    wdgtItemForTest: cc.Widget;
    scIsvCpnt: InfiniteScrollViewCpnt;
    scIndicator: cc.PageViewIndicator;

    private _testData: unknown[];
    private _maxPageScale: number;
    private _minPageScale: number;
    private _isShow: boolean;
    private _totalCount: number;
    private _lastFinalPageIndex: number;

    onLoad() {
        cc.log(`${cc.js.getClassName(this)} onLoad`)

        this.ndItemForTest = cc.find(`ndItemForTest`, this.node)
        this.ndItemForTest.parent = null
        this.wdgtItemForTest = this.ndItemForTest.getComponent(cc.Widget)
        this.wdgtItemForTest.horizontalCenter = 0
        this.wdgtItemForTest.verticalCenter = 0
        if (this.isHorizontal) {
            this.wdgtItemForTest.isAlignHorizontalCenter = false
            this.wdgtItemForTest.isAlignVerticalCenter = true
        } else {
            this.wdgtItemForTest.isAlignHorizontalCenter = true
            this.wdgtItemForTest.isAlignVerticalCenter = false
        }

        // IsvCpnt
        this.scIsvCpnt = cc.instantiate(this.pfbIsvCpnt).getComponent(this.pfbIsvCpnt.name)
        this.ndIsvCpntCtn.addChild(this.scIsvCpnt.node)
        this.scIsvCpnt.setMaskEnabled(false)
        this.scIsvCpnt.affectedByScale = this.affectedByScale

        //indicator
        if (this.isIndicatorActive) {
            this.scIndicator = this.indicator.getComponent(`PageIndicator`)
            this.scIndicator.setPageView(this as any)
        }


        // Test
        // this._testData = []
        // for (let index = 0; index < 10; index++) {
        //     this._testData.push(index)
        // }
        // this.scIsvCpnt.setPageExtraMode(`Scale`, this._maxPageScale || 1, this._minPageScale || 0.8)
        // // this.scIsvCpnt.setItemSpace(this.itemSpace)
        // this.scIsvCpnt.setItemSpace(-300)
        // this.setAutoPageTime(this.autoPageTime)
        // this.init(this._testData.length, (index) => {
        //     // cc.log(`${cc.js.getClassName(this)} _createCall index = ${index}`)

        //     let item = this.getItemFromPoolWithName(this.ndItemForTest.name) || cc.instantiate(this.ndItemForTest),
        //         lab = item.getChildByName(`lab`).getComponent(cc.Label)
        //     item.color = index % 2 === 0 ? cc.color(255, 0, 0) : cc.color(0, 255, 0)
        //     lab.string = this._testData[index].toString()

        //     return {
        //         item: item,
        //         poolName: item.name,
        //     }
        // }, (item: cc.Node, index: number, isActive: boolean) => {
        //     // cc.log(`${cc.js.getClassName(this)} _activeCall index = ${index} isActive = ${isActive}`)

        // }, (item: cc.Node, index: number, isCurPage: boolean, isFinalPage: boolean) => {
        //     if (isFinalPage) {
        //         // cc.log(`${cc.js.getClassName(this)} onPage index = ${index}`)
        //     }
        // }, this.isHorizontal)
    }

    // ====================================================================================
    // ===================================== 内部接口 ======================================
    // ====================================================================================

    // ====================================================================================
    // ===================================== 外部接口 ======================================
    // ====================================================================================

    /**
     * 显示
     * @returns {Boolean} 是否显示
     */
    show() {
        // cc.log(`${cc.js.getClassName(this)} show`)

        this._isShow = true
        this.node.active = this._isShow

        return this._isShow
    }

    /**
     * 隐藏
     * @returns {Boolean} 是否显示
     */
    hide() {
        // cc.log(`${cc.js.getClassName(this)} hide`)

        this._isShow = false
        this.node.active = this._isShow

        return this._isShow
    }

    /**
     * @returns {Boolean} 是否显示
     */
    isShow() {
        // cc.log(`${cc.js.getClassName(this)} isShow`)

        return this._isShow
    }

    /**
     * 初始化无限滑动列表
     * @param totalCount 列表节点数量
     * @param createCall 滑动节点创建回调 createCall(index 节点索引) return {item, poolName}
     * @param activeCall 进入或离开视窗的回调 activeCall(item 节点, index 节点索引, isActive 是否显示状态)
     * @param pageCall 轮播回调 activeCall(item 节点, index 节点索引, isCurPage 是否经过当前页, isFinalPage 是否最终到达当前页)
     * @param isHorizontal 是否横向滑动
     * @param infinity 是否无线循环滑动，默认是
     */
    init(totalCount: number, createCall: (index: number) => { item: cc.Node, poolName: string }, activeCall: (item: cc.Node, index: number, isActive: boolean, isIniting: boolean) => void, pageCall: (item: cc.Node, index: number, isCurPage: boolean, isFinalPage: boolean) => void, isHorizontal = false, infinity = true) {
        cc.log(`${cc.js.getClassName(this)} init`)
        this._totalCount = totalCount

        this.isIndicatorActive && (this.scIndicator as any)._refresh()
        this.isHorizontal = isHorizontal
        this.scIsvCpnt.affectedByScale = this.affectedByScale
        this.infinity = infinity
        this._lastFinalPageIndex = -1
        this.scIsvCpnt.setMode(`Page`, (item, index, isCurPage, isFinalPage) => {
            if (isFinalPage) {
                // cc.log(`${cc.js.getClassName(this)} onPage index = ${index}`)

                let tarIndex = (this.infinity ? this._totalCount : 0) + index % this._totalCount
                if (tarIndex !== index) {
                    this.scIsvCpnt.scrollToIndex(tarIndex)
                } else {
                    if (this._lastFinalPageIndex !== index) {
                        this._lastFinalPageIndex = index
                        pageCall(item, index % this._totalCount, isCurPage, isFinalPage)
                    }
                    if (this.autoPageTime > 0) {
                        this.unscheduleAllCallbacks()
                        this.scheduleOnce(() => {
                            let curPageIndex = this.scIsvCpnt.getCurrentPageIndex()
                            this.scIsvCpnt.scrollToIndex(curPageIndex + 1, AutoPageActionTime)
                        }, this.autoPageTime + AutoPageActionTime)
                    }
                }
                this.isIndicatorActive && (this.scIndicator as any)._changedState()
                // this.scIndicator._refresh();

            } else {
                pageCall(item, index % this._totalCount, isCurPage, isFinalPage)
            }
        })
        this.scIsvCpnt.init(this._totalCount * (this.infinity ? 3 : 1), (index) => {
            // cc.log(`${cc.js.getClassName(this)} _createCall index = ${index}`)

            return createCall(index % this._totalCount)
        }, (item, index, isActive, isIniting) => {
            // cc.log(`${cc.js.getClassName(this)} _activeCall index = ${index} isActive = ${isActive}`)

            activeCall(item, index % this._totalCount, isActive, isIniting)
        }, this.isHorizontal, true)
        this.infinity && this.scIsvCpnt.scrollToIndex(this._totalCount)
        this.unscheduleAllCallbacks()
        if (this.autoPageTime > 0) {
            this.unscheduleAllCallbacks()
            this.scheduleOnce(() => {
                let curPageIndex = this.scIsvCpnt.getCurrentPageIndex()
                this.scIsvCpnt.scrollToIndex(curPageIndex + 1, AutoPageActionTime)
            }, this.autoPageTime + AutoPageActionTime)
        }
        this.scIsvCpnt.bindEventScrollBegan(() => {
            this.unscheduleAllCallbacks()
        })
    }

    /**
     * 设置自动轮播时间，大于0有效
     * @param time 时间
     */
    setAutoPageTime(time: number) {
        cc.log(`${cc.js.getClassName(this)} setAutoPageTime`)

        this.autoPageTime = time || 0
    }

    /**
     * 设置列表项间隔
     * @param itemSpace 间隔
     * @param itemTopOrLeftSpace 首间隔
     * @param itemBottomOrRightSpace 尾间隔
     */
    setItemSpace(itemSpace: number, itemTopOrLeftSpace: number = 0, itemBottomOrRightSpace: number = 0) {
        cc.log(`${cc.js.getClassName(this)} setItemSpace itemSpace = ${itemSpace} itemTopOrLeftSpace = ${itemTopOrLeftSpace} itemBottomOrRightSpace = ${itemBottomOrRightSpace}`)

        this.scIsvCpnt.setItemSpace(itemSpace)
    }

    /**
     * 通过节点池名称从节点池获取节点(如果没有，则需要自行创建，此工具只是代为管理节点池)
     * @param poolName 节点池名称
     */
    getItemFromPoolWithName(poolName: string) {
        // cc.log(`${cc.js.getClassName(this)} getItemFromPoolWithName poolName = ${poolName}`)

        return this.scIsvCpnt.getItemFromPoolWithName(poolName)
    }

    /**
     * 设置轮播额外效果模式
     * @param pageExtraMode 模式，根据不同类型需要额外传入不同参数
     * cc.InfiniteScrollViewCpnt.PageExtraMode.Nomal 无额外参数
     * cc.InfiniteScrollViewCpnt.PageExtraMode.Scale MaxPageScale 最大比例, MinPageScale 最小比例
     */
    setPageExtraMode(pageExtraMode: IsvPageExtraMode = `Nomal`, maxPageScale: number = 0, minPageScale: number = 0) {
        cc.log(`${cc.js.getClassName(this)} setPageExtraMode pageExtraMode = ${pageExtraMode}`)

        switch (pageExtraMode) {
            case `Scale`:
                this.scIsvCpnt.setPageExtraMode(pageExtraMode, maxPageScale || this._maxPageScale, minPageScale || this._minPageScale)

                break

            default:
                this.scIsvCpnt.setPageExtraMode(pageExtraMode, 1, 1)

                break
        }
    }

    /**
     * 滑动到指定序号节点
     * @param index 序号
     * @param time 滑动时间
     */
    scrollToIndex(index: number, time: number) {
        cc.log(`${cc.js.getClassName(this)} scrollToIndex index = ${index}`)

        this.scIsvCpnt.scrollToIndex(this.infinity ? this._totalCount + index : index, time)
    }

    /**
     * 是否启用组件自带遮罩组件
     * @param bool 是否启用
     */
    setMaskEnabled(bool: boolean) {
        cc.log(`${cc.js.getClassName(this)} setMaskEnabled bool = ${bool}`)

        this.node.getComponent(cc.Mask).enabled = bool
    }

    setIndicatorActive(bool: boolean) {
        cc.log(`${cc.js.getClassName(this)} setIndicatorActive bool = ${bool}`)
        this.isIndicatorActive = bool
    }

    /**
     * 锁定滑动
     * @param bool 是否锁定
     */
    lockScroll(bool: boolean) {
        cc.log(`${cc.js.getClassName(this)} lockScroll bool = ${bool}`)

        this.scIsvCpnt.lockScroll(bool)
    }

    /**
     * 通过序号获取节点
     * @param tarIndex 序号
     */
    getItemByIndex(tarIndex: number) {
        // cc.log(`${cc.js.getClassName(this)} getItemByIndex index = ${index}`)

        return this.scIsvCpnt.getItemByIndex(tarIndex + (this.infinity ? this._totalCount : 0))
    }

    /**
     * 获取当前页面索引
     */
    getCurrentPageIndex() {
        // cc.log(`${cc.js.getClassName(this)} getCurrentPageIndex`)
        let curIndex = this.scIsvCpnt.getCurrentPageIndex()
        return this.infinity ? curIndex % this._totalCount : curIndex

    }

    getTotalCount() {
        let totalCount = this._totalCount ? this._totalCount : 0
        return totalCount
    }
}